package com.devehx.wallet.serviceimpl;

import com.devehx.wallet.comm.*;
import com.devehx.wallet.model.Dict;
import com.devehx.wallet.model.Recharge;
import com.devehx.wallet.model.UserAddress;
import com.devehx.wallet.repository.DictDao;
import com.devehx.wallet.repository.RechargeDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Slf4j
@Service
public class RechargeServiceImpl implements RechargeService {

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Resource
    private DictDao dictDao;

    @Resource
    private RechargeDao rechargeDao;

    @Resource
    private RechargeService rechargeService;

    /**
     * 获取扫描过的最新区块号码
     */
    @Override
    public int blockNumber() {
        Dict number = dictDao.findByName("block_number");
        return Objects.isNull(number) ? 0 : Integer.parseInt(number.getValue());
    }

    /**
     * 修改扫描过的最新区块号码
     */
    @Override
    public void updateNumber(int number) {
        Dict data = dictDao.findByName("block_number");
        data.setValue(String.valueOf(number));
        dictDao.save(data);
    }

    /**
     * 是否支持本币种
     *
     * @param address 合约地址
     */
    @Override
    public boolean isCoin(String address) {
        return ERC20.isOk(address);
    }

    /**
     * 是否支持这个地址的充值
     *
     * @param ethAddress 地址
     */
    @Override
    public boolean isAddress(String ethAddress) {
        Object[] params = {ethAddress};
        Integer count = jdbcTemplate.queryForObject("select count(*) from eth_user_address where address=?", params, Integer.class);
        return !Objects.isNull(count) && count > 0;
    }

    /**
     * 保存充值记录
     *
     * @param model 实体
     */
    @Override
    public void saveRechargeRecord(Recharge model) {
        Recharge recharge = rechargeDao.findIdByTxHash(model.getTxHash());
        if (!Objects.isNull(recharge)) {
            log.warn("重复数据:{}", model);
            return;
        }
        rechargeDao.save(model);
    }

    /**
     * 查询所有未确认的充值
     */
    @Override
    public List<Recharge> findNoConfirmList() {
        String sql = "select * from eth_recharge where contract ='0xdac17f958d2ee523a2206206994597c13d831ec7' and state = 0";
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Recharge.class));
    }


    /**
     * 修改状态
     *
     * @param id    id
     * @param state 状态
     */
    @Override
    public void changeState(Integer id, RechargeState state) {
        Optional<Recharge> recharge = rechargeDao.findById(id);
        recharge.ifPresent(value -> {
            value.setState(state.state);
            rechargeDao.save(value);
        });
    }

    /**
     * 查询所有的用户账户
     */
    @Override
    public List<UserAddress> findAllAddress() {
        RowMapper<UserAddress> rowMapper = new BeanPropertyRowMapper<>(UserAddress.class);
        return jdbcTemplate.query("SELECT id,user_id,address,privateKey,mnemonic,create_time FROM eth_user_address", rowMapper);
    }

    /**
     * 根据地址查询私钥
     *
     * @param address 地址
     */
    @Override
    public String findKeyByAddress(String address) {
        Object[] params = {address};
        return jdbcTemplate.queryForObject("SELECT privateKey FROM eth_user_address where address=?", params, String.class);
    }

    /**
     * 归集
     *
     * @param recharge 归集信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void collect(Recharge recharge) {
        Wallet dict = rechargeService.getWallet();
        //收款人=需要归集的人
        String receiver = recharge.getReceiver();
        //需要归集的人的eth余额
        BigInteger balanceEth = WalletKit.getBalance(receiver);
        if (balanceEth.compareTo(Const.GAS_COLLECT) < 0) {
            //转手续费
            String tx = WalletKit.transfer(ERC20.ETH.address, dict.getWalletAddress(), dict.getWalletPrivateKey(), receiver, Const.GAS_COLLECT);
            log.warn("用户ETH余额：{}，小于{}，转给用户GAS，交易哈希{}", balanceEth, Const.GAS_COLLECT, tx);
            //标识为暂时不归集
            CollectKit.add(receiver);
            return;
        }
        //查询用户私钥
        String privateKey = rechargeService.findKeyByAddress(receiver);
        //转账数量WEI
        BigInteger num = recharge.getAmount().multiply(ERC20.USDT.decimal).toBigInteger();
        String tx = WalletKit.transfer(ERC20.USDT.address, receiver, privateKey, dict.getCollectAddress(), num);
        log.warn("归集：数量{}个，交易哈希{}", recharge.getAmount(), tx);
        if (WalletKit.isTxHash(tx)) {
            rechargeService.changeCollectOk(recharge.getId());
        }
    }

    /**
     * 查询未归集的充值
     */
    @Override
    public List<Recharge> findNoCollectList() {
        String sql = "select * from eth_recharge" +
                " where contract = '" + ERC20.USDT.address + "' and amount >=1 and is_collect=0 and state in(1,5)";
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Recharge.class));
    }


    /**
     * 获取系统钱包信息
     */
    @Override
    public Wallet getWallet() {
        Wallet model = new Wallet();
        for (Dict dict : dictDao.findAll()) {
            String name = dict.getName();
            if ("collect_address".equalsIgnoreCase(name)) {
                model.setCollectAddress(dict.getValue());
            } else if ("wallet_address".equalsIgnoreCase(name)) {
                model.setWalletAddress(dict.getValue());
            } else if ("wallet_private_key".equalsIgnoreCase(name)) {
                model.setWalletPrivateKey(dict.getValue());
            }
        }
        if (Objects.isNull(model.getCollectAddress())
                || Objects.isNull(model.getWalletAddress()) || Objects.isNull(model.getWalletPrivateKey())) {
            throw new IllegalArgumentException("数据库数据错误");
        }
        return model;
    }

    @Override
    public void changeCollectOk(Integer id) {
        Object[] param = {id};
        jdbcTemplate.update("update eth_recharge set is_collect =1 where id=?", param);
    }

}
